package com.qf.smsplatform.service.Impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qf.smsplatform.cache.BlackListCache;
import com.qf.smsplatform.cache.TMultipleParamsCache;
import com.qf.smsplatform.constans.ResultCode;
import com.qf.smsplatform.events.UpdateBlackEvent;
import com.qf.smsplatform.exception.AddDataException;
import com.qf.smsplatform.exception.MyBaseException;
import com.qf.smsplatform.exception.QueryDataException;
import com.qf.smsplatform.exception.UpdateDataException;
import com.qf.smsplatform.mapper.BlackListMapper;
import com.qf.smsplatform.pojo.CheckType;
import com.qf.smsplatform.pojo.MyAuthUser;
import com.qf.smsplatform.pojo.TBlackList;
import com.qf.smsplatform.pojo.TMultipleParams;
import com.qf.smsplatform.service.BlackListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
/*2021/10/25*/public class BlackListServiceImpl implements BlackListService {

    private BlackListMapper blackListMapper;
    private BlackListCache blackListCache;
    private ApplicationContext context;
    private TMultipleParamsCache multipleParamsCache;

    @Autowired
    public void setMultipleParamsCache(TMultipleParamsCache multipleParamsCache) {
        this.multipleParamsCache = multipleParamsCache;
    }
    @Autowired
    public void setBlackListMapper(BlackListMapper blackListMapper) {
        this.blackListMapper = blackListMapper;
    }
    @Autowired
    public void setBlackListCache(BlackListCache blackListCache) {
        this.blackListCache = blackListCache;
    }
    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    @Override
    public TBlackList findBlackById(Long id) {//根据id进行黑名单信息的查找
        if(ObjectUtils.isEmpty(id)||id<=0){//判断传递过来的主键是否合规
            throw new MyBaseException("传递的主键不合法", ResultCode.PK_NOT_ALLOW);
        }
        //现在是从权限中获取
        MyAuthUser user = (MyAuthUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();//从session中获取
//        TAdminUser user = (TAdminUser)((ServletRequestAttributes) requestAttributes).getRequest().getSession().getAttribute("user");
        TBlackList black = blackListCache.getByKey(id);
        if(user.getType()==1||black.getCreater()==user.getId()){//验证用户是否有权限进行数据查看
            return black;
        }
        throw new QueryDataException("没有权限进行查看", ResultCode.NOT_ALLOW);
    }

    @Override
    public void addBlack(TBlackList black) {//添加一个黑名单信息
        //校验电话号码信息是否符合规则
        if (black.isNull(CheckType.ADD)) {
            //不是合理的手机号
            //抛出异常
            throw new AddDataException("手机号不符合规范", ResultCode.PHONE_NUM_ERROR);
        }
        blackListMapper.addBlack(black);
        //如果走了添加方法的话进行缓存的更新
//        blackListCache.init();//和当前增加绑定一起，为一个线程，两者不应相互影响
//        new Thread(){//新开启一个线程，二者相互不影响
//            @Override
//            public void run() {
//                blackListCache.init();
//            }
//        }.start();

        //发布一个事件
        context.publishEvent(new UpdateBlackEvent());
    }

    @Override
    public PageInfo<TBlackList> selectPage(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);//使用插件进行限定数据的查询
//        List<TBlackList> blackLists = blackListMapper.selectAll();//从数据库获取数据
        List<TBlackList> allBlackList = blackListCache.getAllData();//从缓存中获取数据
        //使用集合的分割功能对集合数据进行分页显示，但是会出现数组下标越界异常
//        List<TBlackList> blackLists = allBlackList.subList((pageNum - 1) * pageSize, pageNum * pageSize);
        //使用集合的stream功能进行分割
//        List<TBlackList> blackLists = allBlackList.stream()
//                .skip((pageNum - 1) * pageSize)
//                .limit(pageSize)
//                .collect(Collectors.toList());
        //存在一个问题就是查询出的数据是所有数据，应该只显示当前用户的数据
        //首先获取当前用户的信息，然后进行判断

//        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//        Object user = ((ServletRequestAttributes) requestAttributes).getRequest().getSession().getAttribute("user");

        MyAuthUser user = (MyAuthUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        //函数是一等公民
        List<TBlackList> collect = allBlackList.stream().filter(blackList -> {
            // 获取到符合当前用户能看到的所有的数据
            return blackList.getOwntype() == 1 || blackList.getCreater() ==  user.getId() ||  user.getType() == 1;
        }).skip((pageNum - 1) * pageSize)
                .limit(pageSize)
                .collect(Collectors.toList());

        PageInfo<TBlackList> pageInfo=new PageInfo<>(collect);//将查询到的数据放入pageinfo中进行传递
        return pageInfo;
    }

    @Override
    public Integer deleteByIds(List<Integer> ids) {

//        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//        TAdminUser user =(TAdminUser) ((ServletRequestAttributes) requestAttributes).getRequest().getSession().getAttribute("user");

        MyAuthUser user = (MyAuthUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        if(user.getType()==1){
            Integer integer = blackListMapper.deleteByAdmin(ids);
            //发布一个事件
            context.publishEvent(new UpdateBlackEvent());
            return integer;
        }
        Integer integer = blackListMapper.deleteByIds(ids, user.getId());
        //发布一个事件,缓存中的内容进行更新
        context.publishEvent(new UpdateBlackEvent());
        return integer;

    }

    @Override
    public void updateBlack(TBlackList tBlackList) {

//        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
//        TAdminUser user =(TAdminUser) ((ServletRequestAttributes) requestAttributes).getRequest().getSession().getAttribute("user");

        MyAuthUser user = (MyAuthUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        //校验电话号码信息是否符合规则
        if (tBlackList.isNull(CheckType.UPDATE)) {
            //不是合理的手机号
            //抛出异常
            throw new AddDataException("手机号不符合规范", ResultCode.DATA_ISNULL);
        }
        if(user.getType()!=1 && user.getId()!= tBlackList.getCreater()){
            throw new UpdateDataException("没有权限进行修改", ResultCode.NOT_ALLOW);
        }
        blackListMapper.updateBlack(tBlackList);
        //发布一个事件
        context.publishEvent(new UpdateBlackEvent());
    }

    @Override
    public List<TBlackList> selectTBlackAndUser() {
        return blackListMapper.selectTBlackAndUser();
    }

    @Override   //自定义查询条件，而不使用客户端传递的多余条件
    public List<TBlackList> selectByMultParams(TBlackList blackList) throws IllegalAccessException, InstantiationException {
        //从动态查询表中拿到我们允许的参数
        TMultipleParams multipleParams = multipleParamsCache.getByKey("t_black_list");
        List<String> allParams=new ArrayList();

        String params = multipleParams.getParams();
        String[] split = params.split(",");//对数据库中存储的参数列表进行截取
        for (int i=0;i<split.length;i++){//遍历放入集合中便于进行操作
            allParams.add(split[i]);
        }
        //通过类的对象拿到类对象
        Class<? extends TBlackList> blackListClass = blackList.getClass();
        //通过类对象创建出一个实例对象
        TBlackList instance = blackListClass.newInstance();
        allParams.forEach(name->{
            //通过属性名从一个类中获取我们想要的属性
            try {
                PropertyDescriptor descriptor=new PropertyDescriptor(name,blackListClass);
                Method readMethod = descriptor.getReadMethod();//获取属性描述器的写方法/set方法
                Method writeMethod = descriptor.getWriteMethod();//获得get方法
                writeMethod.invoke(instance, readMethod.invoke(blackList));
            } catch (IntrospectionException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        });
        List<TBlackList> blackLists = blackListMapper.selectByMultParams(instance);
        return blackLists;
    }
}
